package cn.autumnorange.app.common.rpc.security;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.PortResolver;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.MalformedURLException;
import java.net.URL;

@Slf4j
public class HttpSessionRequestCacheWrapper implements RequestCache {

  //  public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
  //    super.saveRequest(request, response);
  //
  //    log.info("消费端获取到的sessionId: " + request.getSession(false).getId());
  //    log.info(
  //        "SPRING_SECURITY_SAVED_REQUEST "
  //            + request.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST"));
  //  }

  static final String SAVED_REQUEST = "SPRING_SECURITY_SAVED_REQUEST";
  protected final Log logger = LogFactory.getLog(this.getClass());
  private PortResolver portResolver = new PortResolverImpl();
  private boolean createSessionAllowed = true;
  private RequestMatcher requestMatcher;
  private String sessionAttrName;

  public HttpSessionRequestCacheWrapper() {
    this.requestMatcher = AnyRequestMatcher.INSTANCE;
    this.sessionAttrName = "SPRING_SECURITY_SAVED_REQUEST";
  }

  /**
   * 请求需要权限时,保存当前请求到session缓存请求接口改为由网关路由
   *
   * @param request
   * @param response
   */
  public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
    if (this.requestMatcher.matches(request)) {
      ConsumerSavedRequest savedRequest =
          new ConsumerSavedRequestImpl(request, this.portResolver);
      String urlS = savedRequest.getRequestURL();
      try {
        URL url = new URL(urlS);
        String host = url.getHost();
        if (!savedRequest.getHost().equals(host)) {
          urlS =
                  savedRequest.getProtocol()+"://"
                  + savedRequest.getHost()
                  + savedRequest.getGatewayRoteUrl()
                  + url.getFile();
          savedRequest.setRequestURL(urlS);
          savedRequest.setServerName(
                  savedRequest.getHost() + savedRequest.getGatewayRoteUrl());
        }

        if (this.createSessionAllowed || request.getSession(false) != null) {
          request.getSession().setAttribute(this.sessionAttrName, savedRequest);
          this.logger.debug("DefaultSavedRequest added to Session: " + savedRequest);
        }
      } catch (MalformedURLException e) {
        e.printStackTrace();
      }

    } else {
      this.logger.debug("Request not saved as configured RequestMatcher did not match");
    }
  }

  public SavedRequest getRequest(HttpServletRequest currentRequest, HttpServletResponse response) {
    HttpSession session = currentRequest.getSession(false);
    return session != null ? (SavedRequest) session.getAttribute(this.sessionAttrName) : null;
  }

  public void removeRequest(HttpServletRequest currentRequest, HttpServletResponse response) {
    HttpSession session = currentRequest.getSession(false);
    if (session != null) {
      this.logger.debug("Removing DefaultSavedRequest from session if present");
      session.removeAttribute(this.sessionAttrName);
    }
  }

  public HttpServletRequest getMatchingRequest(
      HttpServletRequest request, HttpServletResponse response) {
    ConsumerSavedRequestImpl saved = (ConsumerSavedRequestImpl) this.getRequest(request, response);
    if (saved == null) {
      return null;
    } else if (!saved.doesRequestMatch(request, this.portResolver)) {
      this.logger.debug("saved request doesn't match");
      return null;
    } else {
      this.removeRequest(request, response);
      return new SavedRequestAwareWrapper(saved, request);
    }
  }

  public void setRequestMatcher(RequestMatcher requestMatcher) {
    this.requestMatcher = requestMatcher;
  }

  public void setCreateSessionAllowed(boolean createSessionAllowed) {
    this.createSessionAllowed = createSessionAllowed;
  }

  public void setPortResolver(PortResolver portResolver) {
    this.portResolver = portResolver;
  }

  public void setSessionAttrName(String sessionAttrName) {
    this.sessionAttrName = sessionAttrName;
  }
}
